<?php
//No Direct Call
if(!defined('MY_ROOT'))
    die();

/**
 * The Table Editor Class.
 * This Class cannot be contructed. Some Other class must Inherit this class to make it work.
 *
 * @author Zhu Chen <zhuchen@greatqq.com>
 * @package Table Editor
 * @version 0.1.0
 * @since 2017 Dec.9
 * @abstract
 */
abstract class TableEditor {
    /**
     * The Table name of of the table Editor
     * @var string 
     */
    protected  $tablename ='';
    
    /**
     *  The display sting of add button
     * @var string 
     */
    public $btnadd_display = '';
    
    /**
     * The display string of delete button
     * @var string 
     */
    public $btndel_display = '';
    
    /**
     * The display string of search button
     * @var string
     */
    public  $btnsearch_display ='';
    
    /**
     * The display string of the modify button
     * @var string 
     */
    public  $btnmod_display = '';

    /**
     * The title to be displayed on the page
     * @var string  
     */
    public $title = '';
    
    /**
     * The search column
     * @var string 
     */
    protected $qsearch_col = '';
    
    /**
     * The column properties, all column includes the ID
     * @var \ColumnProterty 
     */
    protected $columns = array();
    
    /**
     * The key of the database table
     * @var string 
     */
    protected $key_col = 'id';

    /**
     * The table should be set when construction
     * @param string $table
     */
    protected function __construct(string $table) {
        $this->tablename = $table;
    }
    
    /**
     * Add a line of data
     * @param array $line_data
     */
    public function add(array $line_data)    {
        $data = $this->_get_sql_from_data($line_data);
        if(isset($data[$this->key_col])) {
            unset($data[$this->key_col]);
        }
        DB::insert($this->tablename, $data);
    }
    
    /**
     * List a range in the table
     * @param int $rstart The start
     * @param int $rend The end, -1 for till last
     * @return mixed array
     */
    public function lists(int $rstart,int $rend){
        $data =  DB::select($this->tablename, '1', $this->key_col.' DESC LIMIT '.$rstart.','.($rend-$rstart));
        return $this->_get_display_from_data($data);
    }
    
    /**
     * Quick Search on the table
     * @param string $condition The search Condition 
     * @param string $order Either DESC or ASC
     * @return mixed Search Result
     */
    public function qsearch(string $condition,string $order='DESC'){
        if (is_numeric($condition)) {
            $rslt = DB::select($this->tablename, $this->key_col.' = '. intval($condition));
        }else {
            $cond = preg_replace('/\*+/', '%', $condition);
            $o = in_array($order, ['ASC','DESC']) ? $order : 'DESC';
            $rslt = DB::select($this->tablename, $this->qsearch_col.' LIKE ' . DB::get_str($cond) ,'`'.$this->key_col.'` '.$o);
        }
        return $this->_get_display_from_data($rslt);
    }
    
    /**
     * Modify a lone of data in the database
     * @param array $line_data The data to be modified
     */
    public function update(array $line_data){
        $data = $this->_get_sql_from_data($line_data,FALSE);
        $id = $data[$this->key_col]?? FALSE;
        if($id)
        {
            unset($data[$this->key_col]);
        }else{
            throw new InvalidArgumentException("The key is not set. in calling TableEditor::update");
        }
        DB::update($this->tablename,$data,'`'.$this->key_col.'` = '.$id);
        
    }
    
    /**
     * Delete a line
     * @param int $key
     * @throws InvalidArgumentException
     */
    public function delete(int $key)    {
        if($key<1){
            throw new InvalidArgumentException("The key should not less than 1");
        }
        DB::delete($this->tablename,'`'.$this->key_col.'` = '.$key);
    }
    
    public function advsearch(array $condition)    {
        
        foreach($condition as $cond)
        {
            
        }
        
    }
    
    protected function _get_sql_from_data(array $line_data,bool $keepnull = true)    {
        $data = [];
        foreach ($this->columns as $col)  {
            if ($col instanceof ColumnProperty) {
                $data[$col->dbcol] = $col->GetSQLString($line_data[$col->name] ?? NULL);
                if (empty($data[$col->dbcol])&&(!$keepnull)) {
                    unset($data[$col->dbcol]);
                } 
        }else{
                trigger_error(_("An Error occurred in the column configuration in the table editor. The value is ").var_export($col),E_USER_WARNING);
            }
        }
        return $data;
    }
    
    /**
     * Convert the data string
     * @param array $data
     * @return array
     */
    protected function _get_display_from_data(array $data)    {
        $i=0;
        $data_new = [];
        foreach ($data as $datum) {
            foreach ($this->columns as $col)  {
                if($col instanceof ColumnProperty) {
                    $data_new[$i][$col->name] = $col->GetDisplayString($datum[$col->dbcol]);
                }else{
                    trigger_error(_("An Error occurred in the column configuration in the table editor. The value is ").var_export($col),E_USER_WARNING);
                }
            }
            $i++;
        }
        return $data_new;
    }
    
    /**
     * Retive all the columns
     * @return ColumnProperty[]
     */
    public function getColumns()   {
        return $this->columns;
    }
    
    /**
     * Retive the column 
     * @return array
     */
    public function getColumnFields()    {
        $rtn = array();
        $i = 0;
        foreach ($this->columns as $col)
        {
            if($col instanceof ColumnProperty) {
                    $rtn['names'][$i] = $col->name;
                    $rtn['types'][$i] = $this->_col_type_to_string($col->type);
                    $rtn['display'][$i] = $col->display;
                }else{
                    trigger_error(_("An Error occurred in the column configuration in the table editor. The value is ").var_export($col),E_USER_WARNING);
                }
            $i++;
        }
        return $rtn;
    }
    
    
    
    private function _col_type_to_string(int $type) : string   {
        switch ($type)
        {
            case ColumnProperty::COL_PROP_INT:
                return 'int';
            case ColumnProperty::COL_PROP_SERIALIZED:
                return 'callback';
            case ColumnProperty::COL_PROP_STRING:
                return 'string';
            case ColumnProperty::COL_PROP_TEXT:
                return 'raw';
            case ColumnProperty::COL_PROP_TIMESTAMP;
                return 'time';
            
        }
    }
    
}
